package com.demo.exception;

import com.demo.common.ResultData;
import com.demo.config.I18nHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * @author wangfengchen
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

  @Autowired
  private I18nHelper i18nHelper;

  @ExceptionHandler({BindException.class, ConstraintViolationException.class})
  public ResultData<Object> validatorExceptionHandler(Exception e) {
    String msg = e instanceof BindException ?
        msgConvertor(((BindException) e).getBindingResult()) :
        msgConvertor(((ConstraintViolationException) e).getConstraintViolations());
    return ResultData.fail(msg);
  }

  @ExceptionHandler(MissingServletRequestParameterException.class)
  public ResultData<Void> handleException(MissingServletRequestParameterException exception) {
    log.error("异常 = {}", ExceptionUtils.getStackTrace(exception));
    String errMsg = i18nHelper.getMessage("parameter.not.empty", exception.getParameterName());
    return ResultData.fail(errMsg);
  }

  @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
  public ResultData<Void> handleException(HttpRequestMethodNotSupportedException exception) {
    log.error("异常 = {}", ExceptionUtils.getStackTrace(exception));
    String errMsg = i18nHelper.getMessage("method.not.supported", exception.getMethod());
    return ResultData.fail(errMsg);
  }

  @ExceptionHandler(MethodArgumentTypeMismatchException.class)
  public ResultData<Void> handleException(MethodArgumentTypeMismatchException exception) {
    log.error("异常 = {}", ExceptionUtils.getStackTrace(exception));
    String errMsg = i18nHelper.getMessage("method.argument.type.mismatch", exception.getName());
    return ResultData.fail(errMsg);
  }

  @ExceptionHandler(HttpMessageNotReadableException.class)
  public ResultData<Void> handleException(HttpMessageNotReadableException exception) {
    log.error("异常 = {}", ExceptionUtils.getStackTrace(exception), exception);
    String errMsg = i18nHelper.getMessage("parameter.type.error");
    return ResultData.fail(errMsg);
  }

  @ExceptionHandler({Exception.class})
  public ResultData<Object> exceptionHandler(Exception e) {
    log.error("系统异常，e = {}", ExceptionUtils.getStackTrace(e));
    return ResultData.fail("system.error");
  }

  /**
   * 自定义业务异常
   *
   * @param e
   * @return
   */
  @ExceptionHandler(BizException.class)
  public ResultData<Void> handleException(BizException e) {
    log.error("业务异常，e = {}", ExceptionUtils.getStackTrace(e));
    return ResultData.fail(e.getCode(), e.getMessage());
  }

  private String msgConvertor(BindingResult bindingResult) {
    List<FieldError> fieldErrors = bindingResult.getFieldErrors();
    StringBuilder sb = new StringBuilder();
    fieldErrors.forEach(fieldError -> sb.append(fieldError.getDefaultMessage()).append(","));
    return sb.deleteCharAt(sb.length() - 1).toString().toLowerCase();
  }

  private String msgConvertor(Set<ConstraintViolation<?>> constraintViolations) {
    StringBuilder sb = new StringBuilder();
    constraintViolations.forEach(violation -> sb.append(violation.getMessage()).append(","));
    return sb.deleteCharAt(sb.length() - 1).toString().toLowerCase();
  }


}
